Skip to main content

Oracle Fusion Cloud

This guide walks you through the steps required to connect Docflo.ai to your Oracle Fusion Cloud system, enabling seamless document integration and automated invoice processing.

πŸ“‹ Prerequisites:
  • Oracle Fusion Cloud instance with REST API access
  • Visual Studio or development environment for .NET
  • Docflo.ai account with API access
  • Oracle Fusion user with appropriate privileges
  • SSL certificate management capabilities

πŸš€ Integration Steps​

Follow these steps to establish a secure connection between Docflo.ai and your Oracle Fusion system:

Step 1: Import SSL Certificate Chain​

  1. Download our SSL certificate chain (link)
  2. Import the certificate to the Windows Certificate Store on your integration server
  3. Add the certificate to Trusted Root Certification Authorities
  4. Ensure the certificate is properly validated for HTTPS connections

Step 2: Configure Oracle Fusion REST API Access​

  1. Enable REST API services in your Oracle Fusion instance
  2. Create integration user with appropriate roles and privileges
  3. Configure authentication (Basic Authentication or OAuth 2.0)
  4. Test API connectivity using tools like Postman

Step 3: Generate API Credentials​

  1. Go to the "Integrations" section in your Docflo.ai platform
  2. Create an API key for Oracle Fusion integration
  3. Copy the API key and store it securely
  4. Copy the tenant ID as well - you'll need both for the integration

Step 4: Create Oracle Fusion Integration Service​

Create a Windows Service or scheduled application using REST API calls. Here's a sample C# implementation:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net.Http.Headers;

namespace DocfloOracleFusionIntegration
{
public class DocfloFusionIntegrationService
{
private readonly string _docfloApiUrl;
private readonly string _tenantId;
private readonly string _apiKey;
private readonly string _fusionBaseUrl;
private readonly string _fusionUsername;
private readonly string _fusionPassword;
private readonly HttpClient _httpClient;
private readonly HttpClient _fusionClient;

public DocfloFusionIntegrationService(string docfloApiUrl, string tenantId, string apiKey,
string fusionBaseUrl, string fusionUsername, string fusionPassword)
{
_docfloApiUrl = docfloApiUrl;
_tenantId = tenantId;
_apiKey = apiKey;
_fusionBaseUrl = fusionBaseUrl;
_fusionUsername = fusionUsername;
_fusionPassword = fusionPassword;

// Initialize Docflo HTTP client
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("x-tenant-id", _tenantId);
_httpClient.DefaultRequestHeaders.Add("apiKey", _apiKey);

// Initialize Fusion HTTP client with basic authentication
_fusionClient = new HttpClient();
var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_fusionUsername}:{_fusionPassword}"));
_fusionClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);
_fusionClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}

public async Task<List<DocfloDocument>> GetDocfloDocuments(string documentType, bool includeResults = true)
{
try
{
string url = $"{_docfloApiUrl}/docs/v1/document?type={documentType}&includeResults={includeResults}";

HttpResponseMessage response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();

string jsonContent = await response.Content.ReadAsStringAsync();
var docfloResponse = JsonConvert.DeserializeObject<DocfloResponse>(jsonContent);

return docfloResponse.Data;
}
catch (Exception ex)
{
Console.WriteLine($"Error fetching Docflo documents: {ex.Message}");
return new List<DocfloDocument>();
}
}

public async Task<bool> CreateSupplierInvoice(DocfloDocument document)
{
try
{
// Extract data from Docflo document results
var extractedData = ExtractInvoiceData(document);

// Create supplier invoice payload
var invoicePayload = new
{
InvoiceNumber = extractedData.InvoiceNumber,
InvoiceDate = extractedData.InvoiceDate?.ToString("yyyy-MM-dd") ?? DateTime.Now.ToString("yyyy-MM-dd"),
Supplier = extractedData.SupplierNumber,
SupplierSite = extractedData.SupplierSite ?? "DEFAULT",
InvoiceAmount = extractedData.Total,
InvoiceCurrencyCode = extractedData.CurrencyCode ?? "USD",
PaymentTerms = extractedData.PaymentTerms ?? "NET30",
Description = $"Invoice processed from Docflo document {document.Id}",
InvoiceLines = extractedData.LineItems.Select(line => new
{
LineNumber = line.LineNumber,
LineAmount = line.LineTotal,
Description = line.Description,
DistributionCombination = line.AccountCombination ?? "01-000-1000-0000-000",
TaxClassificationCode = line.TaxCode
}).ToArray(),
// Custom attribute for Docflo tracking
AttributeCategory = "DOCFLO",
Attribute1 = document.Id
};

string jsonPayload = JsonConvert.SerializeObject(invoicePayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");

string fusionUrl = $"{_fusionBaseUrl}/fscmRestApi/resources/11.13.18.05/invoices";

HttpResponseMessage response = await _fusionClient.PostAsync(fusionUrl, content);

if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Supplier Invoice created successfully for document {document.Id}");
Console.WriteLine($"Response: {responseContent}");
return true;
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error creating Supplier Invoice: {response.StatusCode}");
Console.WriteLine($"Error details: {errorContent}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception creating Supplier Invoice: {ex.Message}");
return false;
}
}

public async Task<bool> CreateCustomerInvoice(DocfloDocument document)
{
try
{
// Extract data from Docflo document results
var extractedData = ExtractInvoiceData(document);

// Create customer invoice payload
var invoicePayload = new
{
TransactionNumber = extractedData.InvoiceNumber,
TransactionDate = extractedData.InvoiceDate?.ToString("yyyy-MM-dd") ?? DateTime.Now.ToString("yyyy-MM-dd"),
TransactionType = "Invoice",
BillToCustomerNumber = extractedData.CustomerNumber,
BillToSite = extractedData.CustomerSite ?? "DEFAULT",
TransactionCurrencyCode = extractedData.CurrencyCode ?? "USD",
PaymentTerms = extractedData.PaymentTerms ?? "NET30",
Comments = $"Invoice processed from Docflo document {document.Id}",
TransactionLines = extractedData.LineItems.Select((line, index) => new
{
LineNumber = index + 1,
LineType = "LINE",
Description = line.Description,
Quantity = line.Quantity,
UnitSellingPrice = line.UnitPrice,
MemoLineType = "LINE"
}).ToArray(),
// Custom attribute for Docflo tracking
AttributeCategory = "DOCFLO",
Attribute1 = document.Id
};

string jsonPayload = JsonConvert.SerializeObject(invoicePayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");

string fusionUrl = $"{_fusionBaseUrl}/fscmRestApi/resources/11.13.18.05/receivablesInvoices";

HttpResponseMessage response = await _fusionClient.PostAsync(fusionUrl, content);

if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Customer Invoice created successfully for document {document.Id}");
Console.WriteLine($"Response: {responseContent}");
return true;
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error creating Customer Invoice: {response.StatusCode}");
Console.WriteLine($"Error details: {errorContent}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception creating Customer Invoice: {ex.Message}");
return false;
}
}

private FusionInvoiceData ExtractInvoiceData(DocfloDocument document)
{
var data = new FusionInvoiceData();
data.LineItems = new List<FusionInvoiceLineItem>();

// Extract data from Docflo results
if (document.DocfloResults?.ModelFields?.Items?.Value != null)
{
foreach (var item in document.DocfloResults.ModelFields.Items.Value)
{
var description = item.ValueObject?.Description;
if (description != null)
{
switch (description.Type?.ToLower())
{
case "supplier_number":
case "vendor_number":
data.SupplierNumber = description.ValueString;
break;
case "customer_number":
data.CustomerNumber = description.ValueString;
break;
case "supplier_site":
case "vendor_site":
data.SupplierSite = description.ValueString;
break;
case "customer_site":
data.CustomerSite = description.ValueString;
break;
case "invoice_number":
case "document_number":
data.InvoiceNumber = description.ValueString;
break;
case "invoice_date":
case "document_date":
if (DateTime.TryParse(description.ValueString, out DateTime invoiceDate))
{
data.InvoiceDate = invoiceDate;
}
break;
case "currency_code":
case "currency":
data.CurrencyCode = description.ValueString;
break;
case "payment_terms":
data.PaymentTerms = description.ValueString;
break;
case "total":
case "total_amount":
case "gross_amount":
if (double.TryParse(description.ValueString, out double total))
{
data.Total = total;
}
break;
case "item_description":
case "product_description":
case "line_description":
// Create new line item
var lineItem = new FusionInvoiceLineItem
{
LineNumber = data.LineItems.Count + 1,
Description = description.ValueString,
Quantity = 1, // Default quantity
UnitPrice = 0, // Default price
LineTotal = 0 // Default total
};
data.LineItems.Add(lineItem);
break;
case "quantity":
// Update last line item quantity
if (data.LineItems.Count > 0 && double.TryParse(description.ValueString, out double quantity))
{
data.LineItems[data.LineItems.Count - 1].Quantity = quantity;
}
break;
case "unit_price":
case "price":
// Update last line item price
if (data.LineItems.Count > 0 && double.TryParse(description.ValueString, out double unitPrice))
{
data.LineItems[data.LineItems.Count - 1].UnitPrice = unitPrice;
}
break;
case "line_total":
case "amount":
// Update last line item total
if (data.LineItems.Count > 0 && double.TryParse(description.ValueString, out double lineTotal))
{
data.LineItems[data.LineItems.Count - 1].LineTotal = lineTotal;
}
break;
case "account_combination":
case "gl_account":
// Update last line item account
if (data.LineItems.Count > 0)
{
data.LineItems[data.LineItems.Count - 1].AccountCombination = description.ValueString;
}
break;
case "tax_code":
case "vat_code":
// Update last line item tax code
if (data.LineItems.Count > 0)
{
data.LineItems[data.LineItems.Count - 1].TaxCode = description.ValueString;
}
break;
}
}
}
}

return data;
}

public void Dispose()
{
_httpClient?.Dispose();
_fusionClient?.Dispose();
}
}

// Data models
public class DocfloResponse
{
[JsonProperty("data")]
public List<DocfloDocument> Data { get; set; }
}

public class DocfloDocument
{
[JsonProperty("_id")]
public string Id { get; set; }

[JsonProperty("sourceId")]
public string SourceId { get; set; }

[JsonProperty("sourceDesc")]
public string SourceDesc { get; set; }

[JsonProperty("status")]
public string Status { get; set; }

[JsonProperty("numOfPages")]
public string NumOfPages { get; set; }

[JsonProperty("createdAt")]
public string CreatedAt { get; set; }

[JsonProperty("docflo_results")]
public DocfloResults DocfloResults { get; set; }
}

public class DocfloResults
{
[JsonProperty("modelFields")]
public ModelFields ModelFields { get; set; }
}

public class ModelFields
{
[JsonProperty("Items")]
public ItemsField Items { get; set; }
}

public class ItemsField
{
[JsonProperty("value")]
public List<Item> Value { get; set; }

[JsonProperty("type")]
public string Type { get; set; }
}

public class Item
{
[JsonProperty("type")]
public string Type { get; set; }

[JsonProperty("valueObject")]
public ValueObject ValueObject { get; set; }
}

public class ValueObject
{
[JsonProperty("Description")]
public Description Description { get; set; }
}

public class Description
{
[JsonProperty("type")]
public string Type { get; set; }

[JsonProperty("valueString")]
public string ValueString { get; set; }

[JsonProperty("content")]
public string Content { get; set; }
}

public class FusionInvoiceData
{
public string SupplierNumber { get; set; }
public string CustomerNumber { get; set; }
public string SupplierSite { get; set; }
public string CustomerSite { get; set; }
public string InvoiceNumber { get; set; }
public DateTime? InvoiceDate { get; set; }
public string CurrencyCode { get; set; }
public string PaymentTerms { get; set; }
public double Total { get; set; }
public List<FusionInvoiceLineItem> LineItems { get; set; }
}

public class FusionInvoiceLineItem
{
public int LineNumber { get; set; }
public string Description { get; set; }
public double Quantity { get; set; }
public double UnitPrice { get; set; }
public double LineTotal { get; set; }
public string AccountCombination { get; set; }
public string TaxCode { get; set; }
}

// Main program example
class Program
{
static async Task Main(string[] args)
{
var service = new DocfloFusionIntegrationService(
"https://api.docflo.ai", // Replace with actual Docflo API URL
"your-tenant-id", // Replace with your tenant ID
"your-api-key", // Replace with your API key
"https://your-fusion-instance.oraclecloud.com", // Replace with your Fusion URL
"fusion-username", // Replace with Fusion username
"fusion-password" // Replace with Fusion password
);

try
{
// Get documents from Docflo
var documents = await service.GetDocfloDocuments("invoice", true);

foreach (var document in documents)
{
// Process each document based on type
if (document.Status == "APPROVED")
{
// Create Supplier Invoice for vendor invoices
bool supplierResult = await service.CreateSupplierInvoice(document);

// Or create Customer Invoice for customer invoices
// bool customerResult = await service.CreateCustomerInvoice(document);

if (supplierResult)
{
Console.WriteLine($"Successfully processed document {document.Id}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in main process: {ex.Message}");
}
finally
{
service.Dispose();
}
}
}
}

πŸ”§ Configuration Requirements​

NuGet Packages Required​

Add these NuGet packages to your project:

<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />

Oracle Fusion User Privileges​

Ensure your integration user has the following roles and privileges:

  1. Payables Invoice Entry - For creating supplier invoices
  2. Receivables Invoice Entry - For creating customer invoices
  3. REST API Access - For API connectivity
  4. Integration Specialist - For system integration tasks

Application Configuration​

Create an app.config file with your settings:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="DocfloApiUrl" value="https://api.docflo.ai" />
<add key="TenantId" value="your-tenant-id" />
<add key="ApiKey" value="your-api-key" />
<add key="FusionBaseUrl" value="https://your-fusion-instance.oraclecloud.com" />
<add key="FusionUsername" value="your-fusion-username" />
<add key="FusionPassword" value="your-fusion-password" />
</appSettings>
</configuration>

πŸš€ Deployment Options​

Option 1: Windows Service​

Deploy as a Windows Service for continuous processing:

  1. Install the service using sc create or InstallUtil
  2. Configure service account with appropriate permissions
  3. Set up logging for monitoring and troubleshooting
  4. Schedule regular document polling

Option 2: Azure Function​

Deploy as an Azure Function for cloud-based processing:

  1. Create Azure Function App
  2. Configure timer trigger for scheduled execution
  3. Set application settings for configuration values
  4. Monitor execution through Azure portal

Option 3: Scheduled Task​

Use Windows Task Scheduler for periodic execution:

  1. Create a scheduled task to run the application
  2. Set appropriate triggers (hourly, daily, etc.)
  3. Configure security context for Oracle Fusion access
  4. Monitor execution logs

πŸ“Š Monitoring and Logging​

Implement comprehensive logging using NLog or Serilog:

// Add to your service class
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

public void LogIntegrationActivity(string message, Exception ex = null)
{
if (ex == null)
{
logger.Info(message);
}
else
{
logger.Error(ex, message);
}
}

πŸŽ‰ Integration Complete! Your Oracle Fusion system is now connected to Docflo.ai and can automatically process invoice documents, creating both supplier and customer invoices based on extracted document data.

πŸ” Troubleshooting​

Common Issues​

  1. REST API Authentication Errors:

    • Verify username and password credentials
    • Check user roles and privileges in Fusion
    • Ensure API endpoints are accessible
  2. SSL Certificate Issues:

    • Verify certificate installation in Windows Certificate Store
    • Check certificate chain completeness
    • Ensure proper certificate binding
  3. API Rate Limiting:

    • Implement retry logic with exponential backoff
    • Monitor API usage limits
    • Consider batch processing for large volumes
  4. Data Mapping Issues:

    • Validate extracted data from Docflo documents
    • Check required fields for Fusion invoice creation
    • Ensure proper data type conversions

πŸ“ž Support​

For technical assistance with the Oracle Fusion integration:

  • Contact Docflo.ai support team
  • Consult Oracle Fusion Cloud documentation
  • Review Oracle REST API guides
  • Contact your Oracle implementation partner